<template>
  <!-- 这个版本的bug是曲线向左边更新,但是x轴向右更新 -->
  <div ref="chart"></div>
</template>

<script>
import * as d3 from "d3";

export default {
  data() {
    return {
      data: [], // 存储折线图数据的数组
      xScale: null, // x轴比例尺
      yScale: null, // y轴比例尺
      line: null, // 折线生成器
      path: null, // 折线路径元素
      width: 600, // 图表宽度
      height: 300, // 图表高度
      margin: {
        top: 20,
        right: 20,
        bottom: 40,
        left: 40,
      }, // 图表边距
    };
  },
  mounted() {
    this.initChart();
    setInterval(() => {
      const newData = Math.random(); // 模拟新数据
      this.updateData(newData);
    }, 1000); // 每秒更新一次数据
  },
  methods: {
    initChart() {
      // 创建SVG元素
      const svg = d3
        .select(this.$refs.chart)
        .append("svg")
        .attr("width", this.width)
        .attr("height", this.height);

      // 创建x轴比例尺
      this.xScale = d3
        .scaleTime()
        .range([this.margin.left, this.width - this.margin.right])
        .domain([new Date(Date.now() - 60000), new Date()]);

      // 创建y轴比例尺
      this.yScale = d3
        .scaleLinear()
        .range([this.height - this.margin.bottom, this.margin.top])
        .domain([0, 1]);

      // 创建x轴元素及其标签
      const xAxis = d3
        .axisBottom(this.xScale)
        .tickFormat(d3.timeFormat("%H:%M:%S"));
      svg
        .append("g")
        .attr("class", "x-axis")
        .attr("transform", `translate(0, ${this.height - this.margin.bottom})`)
        .call(xAxis)
        .append("text")
        .attr("class", "axis-label")
        .attr(
          "x",
          (this.width - this.margin.left - this.margin.right) / 2 +
            this.margin.left
        )
        .attr("y", this.margin.bottom - 10)
        .text("Time");

      // 创建y轴元素及其标签
      const yAxis = d3.axisLeft(this.yScale);
      svg
        .append("g")
        .attr("class", "y-axis")
        .attr("transform", `translate(${this.margin.left}, 0)`)
        .call(yAxis)
        .append("text")
        .attr("class", "axis-label")
        .attr(
          "x",
          -(this.height - this.margin.top - this.margin.bottom) / 2 -
            this.margin.top
        )
        .attr("y", -this.margin.left + 10)
        .attr("transform", "rotate(-90)")
        .text("Value");

      // 创建折线生成器
      this.line = d3
        .line()
        .x((d, i) => this.xScale(new Date(Date.now() - (60000 - i * 1000))))
        .y((d) => this.yScale(d))
        .curve(d3.curveMonotoneX);

      // 创建折线路径元素
      this.path = svg
        .append("path")
        .datum(this.data)
        .attr("stroke", "red")
        .attr("fill", "transparent")
        .attr("class", "line")
        .attr("d", this.line);
    },
    updateData(newData) {
      // 添加新数据到数组末尾(path从右到左画)
      this.data.unshift(newData);

      // 更新x轴比例尺域并截取前60秒的数据
      this.xScale.domain([new Date(), new Date(Date.now() - 60000)]);
      if (this.data.length > 60) {
        this.data.pop();
      }

      // 更新x轴标签
      const xAxis = d3
        .axisBottom(this.xScale)
        .tickFormat(d3.timeFormat("%H:%M:%S"));
      d3.select(this.$refs.chart).selectAll(".x-axis").call(xAxis);

      // 更新折线路径
      this.path.datum(this.data).attr("d", this.line);
    },
  },
};
</script>
